#ifndef TEXTURE_HPP
#define TEXTURE_HPP
#include "GLHeaders.hpp"
#include "Color.hpp"
#include "Vector.hpp"
#include "Interpolation.hpp"

// My own Texture class 
// (0,0) is the bottom left corner
// (1,1) is the top right corner
class Texture{
	public:
		GLsizei width;
		GLsizei height;
		Color *data;
	public:
		// Constructor
		Texture(void);
		Texture(
				const GLsizei lengthX,
				const GLsizei lengthY,
				const Color &color = Color::NONE);
    Texture(
        const GLsizei lengthX,
        const GLsizei lengthY,
        const GLfloat fr,
        const GLfloat fg,
        const GLfloat fb,
        const GLfloat fa=1.0f);
    Texture(
        const GLsizei lengthX,
        const GLsizei lengthY,
        const GLint br,
        const GLint bg,
        const GLint bb,
        const GLint ba=0xff);
    Texture(
        const GLsizei lengthX,
        const GLsizei lengthY,
        const GLfloat value);
    Texture(
        const GLsizei lengthX,
        const GLsizei lengthY,
        const GLint value);
    Texture(const Texture &texture);
    
    // Destructor
		~Texture(void);
	
		// Arithmetic operations
		Texture operator + () const;
		Texture operator - () const;
		Texture operator + (const Texture &rhs) const;
		Texture operator + (const Color &value) const;
		Texture operator + (const GLfloat value) const;
    Texture operator + (const GLint value) const;
		Texture operator - (const Texture &rhs) const;
		Texture operator - (const Color &value) const;
		Texture operator - (const GLfloat value) const;
    Texture operator - (const GLint value) const;
		Texture operator * (const Texture &rhs) const;
		Texture operator * (const Color &value) const;
		Texture operator * (const GLfloat value) const;
		Texture operator / (const Texture &rhs) const;
		Texture operator / (const Color &value) const;
		Texture operator / (const GLfloat value) const;

		// Friend Methods
    friend Texture operator + (const Color &value, const Texture &rhs);
    friend Texture operator + (const GLfloat value, const Texture &rhs);
    friend Texture operator + (const GLint value, const Texture &rhs);
	  friend Texture operator - (const Color &value, const Texture &rhs);
	  friend Texture operator - (const GLfloat value, const Texture &rhs);
    friend Texture operator - (const GLint value, const Texture &rhs);
	  friend Texture operator * (const Color &value, const Texture &rhs);
	  friend Texture operator * (const GLfloat value, const Texture &rhs);
	  friend Texture operator / (const Color &value, const Texture &rhs);
	  friend Texture operator / (const GLfloat value, const Texture &rhs);
    
    // Arithmetic updates
    Texture& operator  = (const Texture &rhs);
    Texture& operator  = (const Color &value);
    Texture& operator  = (const GLfloat value);
    Texture& operator  = (const GLint value);
    Texture& operator += (const Texture &rhs);
    Texture& operator += (const Color &value);
    Texture& operator += (const GLfloat value);
    Texture& operator += (const GLint value);
    Texture& operator -= (const Texture &rhs);
    Texture& operator -= (const Color &value);
    Texture& operator -= (const GLfloat value);
    Texture& operator -= (const GLint value);
	  Texture& operator *= (const Texture &rhs);
	  Texture& operator *= (const Color &value);
	  Texture& operator *= (const GLfloat value);
	  Texture& operator /= (const Texture &rhs);
	  Texture& operator /= (const Color &value);
	  Texture& operator /= (const GLfloat value);

    //////////////////////
		// Useful functions //
    //////////////////////
    Texture Fill(const Color &value) const;
		Texture Fill(
        const Color &c0, // bottom left
        const Color &c1, // bottom right
        const Color &c2, // top right
        const Color &c3, // top left
        enum Interp flag=LINEAR) const; 
/*
  	Texture Cloud(
        int octaves=1,
        double persistence=0.5,
        double frequency=2,
				int seed=0,
				GLfloat coefX=1.0f,
				GLfloat coefY=1.0f,
				GLubyte flag=0x0f);
*/
	Texture Radial(
        const Color &c0,
        const Color &c1,
        enum Interp flag=LINEAR) const;
  Texture Line(
        const Vector &v0, // start
        const Vector &v1, // end
        const Color &c0, // start color
        const Color &c1, // end color
        GLfloat w=1.0f, // width
        enum Interp flag=LINEAR) const;
    Texture Rectangle(
        const Vector &v0, // 0 <= v0.x < v1.x < width
        const Vector &v1, // 0 <= v0.y < v1.y < height 
        const Color &c0, // bottom left
        const Color &c1, // bottom right
        const Color &c2, // top right
        const Color &c3, // top left
        enum Interp flag=LINEAR) const;
		Texture Circle(
				const Vector &c, // center
				GLfloat r0, //  0 <= r0 <= min(width,height)
				GLfloat r1, // r0 <= r1 <= min(width,height)
				const Color &c0, // r0 color
        const Color &c1, // r1 color
				enum Interp flag=LINEAR) const;
    Texture Seamless(void) const;
    Texture Inverse(void) const;
    static Texture Add(const Texture &t0, const Texture &t1);
    static Texture Min(const Texture &t0, const Texture &t1);
    static Texture Max(const Texture &t0, const Texture &t1);
/*
		// out = (in1*256)/(in0+1)
		static Texture Divide(Texture &in0,	Texture &in1);
		// out = (in0*in1)/255
		static Texture Multiply(Texture &in0, Texture &in1);	
		// out = (in1*256)/(256-in0)
		static Texture Dodge(Texture &in0, Texture &in1);
		// out = 255-((255-in1)*256)/(in0+1)
		static Texture Burn(Texture &in0, Texture &in1);
		// in0 > 128  :
    //   out = 255 - ((255-in1)*(255-(2*(in0-128))))/256
		// in0 <= 128 :
    //   out = (in1*in0)/128
		static Texture HardLight(Texture &in0, Texture &in1);
		// Rs = (255 - ((255-in1)*(255-in0)))/256
		// out = (((255-in1)*in0*in1)+(in1*Rs))/255
		static Texture SoftLight(Texture &in0, Texture &in1);
		// out = |in1-in0|
		static Texture Difference(Texture &in0, Texture &in1);
		// out = min((in0+in1),255)
		static Texture Addition(Texture &in0, Texture &in1);
		// out = max((in1-in0),0)
		static Texture Substract(Texture &in0, Texture &in1);
		// out = min(in0,in1)
		static Texture Darken(Texture &in0, Texture &in1);
		// out = max(in0,in1)
		static Texture Lighten(Texture &in0, Texture &in1);
*/
};

#endif
